"use strict"

import axios from "axios"

const db = require("../lib/mysql")
const { success, fail, test, render } = require("../lib/result")
const config = require("../config/server.json")
const { passwordHash } = require("./user")
const { setToken } = require("../lib/token")

/* 使用微信注册或登录 typecho，将获得一个两端均可登录的账号，
 * 并返回 token
 */

const loginOrRegister = async function(ctx, next, hasOpenID) {
  let query = ctx.request.body || ctx.request.query

  const dic = {
    code: {
      name: "微信code",
      type: "String",
      required: true
    },

    raw_data: {
      name: "JSON 格式的用户信息",
      type: "String",
      required: true
    },

    username: {
      name: "用户名",
      type: "String"
    },

    password: {
      name: "密码",
      type: "String"
    }
  }

  const queryResult = test(query, dic)
  if (queryResult.success) {
    /* 校验通过，将转化过默认值的 query 返回回来 */
    query = queryResult.msg

    let rawData,
      userInfo = {}
    try {
      rawData = JSON.parse(query.raw_data)
    } catch (err) {
      return fail(28, "raw_data 不是正确的 JSON 格式的用户信息")
    }

    userInfo["name"] = query.username || rawData["nickName"]
    userInfo["password"] = await passwordHash.HashPassword(
      query["password"] || "admin"
    )
    userInfo["screenName"] = rawData["nickName"]
    userInfo["wx_username"] = rawData["nickName"]
    userInfo["wx_avatar"] = rawData["avatarUrl"]
    userInfo["wx_info"] = query.raw_data

    if (!hasOpenID) {
      try {
        let res = await axios.get(
          `https://api.weixin.qq.com/sns/jscode2session?appid=${config.wxapp.appid}&secret=${config.wxapp.secret}&js_code=${query.code}&grant_type=authorization_code`
        )
        if (res.status === 200 && res.data && res.data.openid) {
          userInfo["wx_openid"] = res.data.openid
        } else {
          return fail(30, "openID 获取失败，" + JSON.stringify(res.data))
        }
      } catch (err) {
        return fail(30, "请求失败，" + JSON.stringify(err))
      }
    } else {
      userInfo["wx_openid"] = hasOpenID
    }

    userInfo["group"] = "subscriber"
    userInfo["created"] = parseInt(new Date().valueOf() / 1000)

    const renderData = render(userInfo)

    let existArr = await db.query(
      `SELECT * FROM js_users WHERE name = '${query.username ||
        rawData["nickName"]}' || wx_openid = '${userInfo["wx_openid"] ||
        "wtf"}'`
    )

    let isExist = [...existArr].length > 0
    if (!isExist) {
      const sql = `INSERT INTO js_users (${renderData.key.join(
        ", "
      )}) VALUES (${renderData.val.join(", ")})`

      const res = await db.query(sql)
      if (res.insertId > 0) {
        return success({
          id: res.insertId
        })
      } else {
        return fail(24, res)
      }
    } else {
      delete userInfo["created"]
      delete userInfo["group"]
      delete userInfo["password"]
      userInfo["activated"] = parseInt(new Date().valueOf() / 1000)
      const updateSQL = `UPDATE js_users SET ${render(userInfo, true).join(
        ", "
      )} WHERE name = '${query.username ||
        rawData["nickName"]}' || wx_openid = '${userInfo["wx_openid"] ||
        "wtf"}'`

      const updateRes = await db.query(updateSQL)
      if (updateRes.changedRows === 1) {
        const userId = existArr[0]["uid"]
        const userName =
          existArr[0]["name"] ||
          existArr[0]["screenName"] ||
          existArr[0]["wx_username"]

        return success({
          uid: userId,
          token: setToken(userName, userId, 72)
        })
      }
    }
  } else {
    return fail(22, queryResult.msg)
  }
}

module.exports = {
  loginOrRegister
}
